﻿// HSS.ServiceModel.AuthorizationAttribute.cs
// ----------------------------------------------------------------------------
// Licensed under the MIT license
// http://www.opensource.org/licenses/mit-license.html
// ----------------------------------------------------------------------------
// HighSpeed-Solutions, LLC
// Copyright (c) 2001-2010
// ----------------------------------------------------------------------------
// File:       AuthorizationAttribute.cs
// Author:     HSS\gbanta
// Created:    08/12/2010
// Modified:   05/02/2011
// ----------------------------------------------------------------------------
namespace HSS.ServiceModel
{
	#region Using Directives
	using System;
	using System.Collections.Generic;
	using System.Collections.ObjectModel;
	using System.Linq;
	#endregion

	#region AuthorizationAttribute
	/// <summary>
	/// Identifies a set of roles that are permitted to invoke a method on a service class.
	/// </summary>
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
	public sealed class AuthorizationAttribute : Attribute
	{
		#region Constructors
		/// <summary>
		/// Initializes a new instance of the AuthorizationAttribute attribute with the role or roles in
		/// which the current user must belong to at least one, before a class may be created or a method
		/// may be invoked.
		/// </summary>
		/// <param name="role">The first role.</param>
		/// <param name="role2">The optional second role.</param>
		/// <param name="role3">The optional third role.</param>
		/// <param name="role4">The optional fourth role.</param>
		public AuthorizationAttribute(string role, string role2 = "", string role3 = "", string role4 = "")
		{
			var list = (new string[] { role, role2, role3, role4 })
				.Where((r) => { return !string.IsNullOrEmpty(r); }).ToList();
			this._roles = new ReadOnlyCollection<string>(list);
		}
		#endregion

		#region Properties
		/// <summary>
		/// Gets the roles permitted to invoke a method.
		/// </summary>
		public IEnumerable<string> Roles
		{
			get { return this._roles; }
		} private ReadOnlyCollection<string> _roles;
		#endregion

		#region Methods
		/// <summary>
		/// Determines if the provided <paramref name="usersRoles"/> match any of the
		/// configured <see cref="Roles"/>.
		/// </summary>
		/// <param name="usersRoles">The <paramref name="usersRoles"/> to evaluate.</param>
		/// <returns>true if any of the provided <paramref name="usersRoles"/> match any of the configured <see cref="Roles"/>.</returns>
		public bool IsUserInRole(string[] usersRoles)
		{
			if (this._roles.Count == 0)
				throw new InvalidOperationException("One or more roles must be specified.");

			foreach (string role in this.Roles)
			{
				foreach (var userRole in usersRoles)
				{
					if (userRole.Equals(role, StringComparison.OrdinalIgnoreCase))
						return true;
				}
			}
			return false;
		}
		/// <summary>
		/// Determines if the provided <paramref name="principal"/> is a member of any of the
		/// configured <see cref="Roles"/>.
		/// </summary>
		/// <param name="principal">The <paramref name="principal"/> to evaluate</param>
		/// <returns>true if the provided <paramref name="principal"/> is a member of any of the configured <see cref="Roles"/>.</returns>
		public bool IsUserInRole(System.Security.Principal.IPrincipal principal)
		{
			if (this._roles.Count == 0)
				throw new InvalidOperationException("One or more roles must be specified.");

			foreach (string role in this.Roles)
			{
				if (principal.IsInRole(role))
					return true;
			}
			return false;
		}
		#endregion
	}
	#endregion
}